#pragma once
#include "Mode.h"
#include "lang/System.h"
#include "crypto/CryptoUtil.h"

namespace yzrilyzr_crypto{
	ECLASS(CBC, public Mode){
	private:
	yzrilyzr_array::ByteArray content;
	yzrilyzr_array::ByteArray vector;
	yzrilyzr_array::ByteArray temp;
	void setVector(const yzrilyzr_array::ByteArray & block, u_index off, u_index len){
		yzrilyzr_lang::System::arraycopy(block, off, vector, 0, len);
	}
	public:
	CBC(const yzrilyzr_array::ByteArray & iv, u_index off, u_index len){
		this->vector=yzrilyzr_array::ByteArray(len);
		this->content=yzrilyzr_array::ByteArray(len);
		this->temp=yzrilyzr_array::ByteArray(len);
		setVector(iv, off, len);
	}
	yzrilyzr_array::ByteArray encrypt(const yzrilyzr_array::ByteArray & block, FAQCipherAlgorithm & algorithm)override{
		CryptoUtil::xor (block, vector, temp);
		temp=algorithm.encrypt(temp);
		setVector(temp);
		return temp;
	}
	yzrilyzr_array::ByteArray encryptFinal(const yzrilyzr_array::ByteArray & block, FAQCipherAlgorithm & algorithm)override{
		CryptoUtil:: xor (block, vector, temp);
		temp=algorithm.encrypt(temp);
		setVector(temp);
		return temp;
	}
	yzrilyzr_array::ByteArray decrypt(const yzrilyzr_array::ByteArray & block, FAQCipherAlgorithm & algorithm)override{
		setContent(block);
		temp=algorithm.decrypt(block);
		CryptoUtil:: xor (temp, vector, temp);
		setVector(content);
		return temp;
	}
	yzrilyzr_array::ByteArray decryptFinal(const yzrilyzr_array::ByteArray & block, FAQCipherAlgorithm & algorithm)override{
		setContent(block);
		temp=algorithm.decrypt(block);
		CryptoUtil:: xor (temp, vector, temp);
		setVector(content);
		return temp;
	}
	void setContent(const yzrilyzr_array::ByteArray & block){
		yzrilyzr_lang::System::arraycopy(block, 0, content, 0, content.length);
	}
	void setVector(const yzrilyzr_array::ByteArray & block){
		setVector(block, 0, block.length);
	}
	};
}